<template>
  <view class="l-color-picker">
    <view class="l-color-picker-select">
      <view class="l-color-picker-saturation" :style="'background-color:' + hueColor"></view>
      <movable-area class="l-color-picker-palette">
        <movable-view
          class="l-color-picker-handler"
          direction="all"
          :x="point.x"
          :y="point.y"
          :animation="false"
          :disabled="props.disabled"
          @change="onChangeSB"
        ></movable-view>
      </movable-area>
    </view>
    <view class="l-color-picker-slider-container">
      <view class="l-color-picker-slider-group">
        <l-color-picker-slider
          :disabled="props.disabled"
          :value="point.h"
          type="hue"
          :max="360"
          @change="onChangeHue"
        ></l-color-picker-slider>
        <!-- <l-color-picker-slider
          :disabled="props.disabled"
          :value="point.a"
          :activeColor="colors.rgb"
          type="alpha"
          @change="onChangeAlpha"
        ></l-color-picker-slider> -->
      </view>
      <view class="l-color-picker-color-block">
        <view
          class="l-color-picker-color-block-inner"
          :style="'background-color:' + colors.rgba"
        ></view>
      </view>
    </view>
    <view class="l-color-picker-input-container">
      <view class="l-color-picker-format-select" @click="onFormatChange">
        <text>{{ mode.type }}</text>
        <image
          style="width: 24px; height: 24px; padding-left: 8rpx"
          src=""
        ></image>
      </view>
      <view class="l-color-picker-input">
        <view
          class="l-color-picker-input-item"
          v-for="(item, index) in mode[mode.type]"
          :key="mode.type + index"
        >
          <text class="l-symbol" v-if="mode.type == 'HEX'">#</text>
          <input
            :disabled="props.disabled"
            :type="mode.type == 'HEX' ? 'text' : 'number'"
            :value="mode[mode.type][index]"
            @input="onInput($event, index)"
          />
          <text class="l-symbol" v-if="mode.type == 'HSB' && index">%</text>
        </view>
      </view>
      <view class="l-color-picker-input-item l-color-picker-input-alpha">
        <input
          :disabled="true"
          type="number"
          :value="mode.a"
          @input="onInput($event, 'a')"
        />
        <text class="l-symbol">%</text>
      </view>
    </view>
    <view class="l-color-picker-presets">
      <view class="l-color-picker-presets-box" v-for="list in props.presets" :key="list.label">
        <view class="l-color-picker-presets-label" v-if="list.label">{{ list.label }}</view>
        <view class="l-color-picker-presets-items">
          <block v-if="list.colors.length">
            <view
              class="l-color-picker-color-block l-color-picker-presets-color"
              :class="{
                'l-color-picker-presets-color-checked': [
                  colors.rgba,
                  colors.hsb,
                  colors.hex,
                  colors.HEX,
                ].includes(item),
              }"
              v-for="item in list.colors"
              :key="item"
              @click="onPreset(item)"
            >
              <view
                class="l-color-picker-color-block-inner"
                :style="'background-color:' + item"
              ></view>
            </view>
          </block>
          <text v-else class="l-color-picker-presets-empty">暂无</text>
        </view>
      </view>
    </view>
  </view>
</template>
<script lang="ts">
  import {
    defineComponent,
    onMounted,
    getCurrentInstance,
    reactive,
    watch,
    computed,
    onUnmounted,
  } from 'vue';
  import ColorPickerProps from './props';
  import { useColorState } from './useColorState';
  import { usePointState } from './usePointState';
  import { useFormatState } from './useFormatState';
  import { useState } from './useState';
  import { generateColor, getAlphaColor } from './util';
  import { getRect } from '@/uni_modules/lime-shared/getRect';
  import { debounce } from '@/uni_modules/lime-shared/debounce';
  import { throttle } from '@/uni_modules/lime-shared/throttle';
  import LColorPickerSlider from '../l-color-picker-slider/l-color-picker-slider.vue';

  const name = 'l-color-picker';
  export default defineComponent({
    props: ColorPickerProps,
    name,
    emits: ['change', 'formatChange', 'update:modelValue'],
    setup(props, { emit }) {
      const context = getCurrentInstance();
      const picker = reactive({
        height: 0,
        width: 0,
        radius: 0,
      });
      const [isInput, changeState] = useState();
      const [color, setColorValue] = useColorState('#1677ff', {
        value: props.value || props.modelValue,
        defaultValue: props.defaultColor,
        immediate: true,
      });
      const [point, setPointValue] = usePointState(color, picker);
      const [mode, setFormatValue, onFormatChange] = useFormatState(color, (type) =>
        emit('formatChange', type),
      );

      const hueColor = computed(() => {
        const { h = 0 } = colors.value.Hsb;
        return generateColor({
          h,
          s: 100,
          b: 100,
        }).toRgbString();
      });
      const colors = computed(() => {
        const rgba = color.value?.toRgbString();
        const hex = color.value?.toHexString();
        return {
          rgba,
          rgb: rgba?.replace(/\d(\.\d+)?\)$/, '1)'),
          hex,
          HEX: hex.toUpperCase(),
          hsb: color.value?.toHsbString(),
          a: getAlphaColor(color.value),
          Hsb: color.value.toHsb(),
          Rgb: color.value.toRgb(),
        };
      });

      const setHsbValue = (hsba: { s?: number; b?: number; h?: number; a?: number }) => {
        setColorValue(Object.assign({}, colors.value.Hsb, hsba));
      };

      const onChangeSB = ({ detail }: WechatMiniprogram.TouchEvent) => {
        if (isInput.value) return;
        const { x, y } = detail;
        const s = Math.max(0, x / picker.width);
        const b = Math.max(0, 1 - y / picker.height);
        setHsbValue({ s, b });
        setFormatValue();
      };
      const onChangeHue = (h: number) => {
        if (isInput.value) return;
        setHsbValue({ h });
        setFormatValue();
      };
      const onChangeAlpha = (a: number) => {
        if (isInput.value) return;
        setHsbValue({ a: a / 100 });
        setFormatValue();
      };

      const onInput = debounce((e: WechatMiniprogram.TouchEvent, key: string | number) => {
        changeState();
        const { value } = e.detail;
        if (key == 'a') {
          setHsbValue({ a: value / 100 });
          Object.assign(point, { a: Number(value) });
        } else if (mode.type == mode.types[0]) {
          if ([3, 6, 8].includes(value.length)) {
            setColorValue(value);
            setPointValue();
          }
        } else {
          const isRgb = mode.type == mode.types[1];
          const keys = mode.type.toLowerCase().split('');
          const obj = isRgb ? colors.value?.Rgb : colors.value?.Hsb;
          obj[keys[key]] = Number(key > 0 && !isRgb ? value / 100 : value);
          setColorValue(obj);
          setPointValue();
        }
      });

      const onPreset = (color: string) => {
        if (props.disabled) return;
        changeState();
        setColorValue(color);
        setPointValue();
        setFormatValue();
      };
      const stopWatchValue = watch(
        () => props.modelValue,
        (v) => {
          if (v !== mode.value) {
            setColorValue(v);
            setPointValue();
          }
        },
      );
      const stopWatch = watch(color, (v) => {
        emit('change', v);
        if (props.modelValue && props.modelValue !== mode.value) {
          emit('update:modelValue', mode.value);
        }
      });
      const getPickerSize = throttle(() => {
        Promise.all(
          ['palette', 'handler'].map((item) => getRect(`.${name}-${item}`, { context })),
        ).then(([palette, handler]) => {
          picker.width = Number(palette.width.toFixed(2)) - handler.width;
          picker.height = Number(palette.height.toFixed(2)) - handler.height;

          setPointValue();
          setFormatValue();
        });
      }, 300);
      onUnmounted(() => {
        stopWatch();
        stopWatchValue();
      });
      onMounted(getPickerSize);
      return {
        props,
        color,
        hueColor,
        colors,
        point,
        mode,
        onChangeSB,
        onChangeHue,
        onChangeAlpha,
        onFormatChange,
        onInput,
        onPreset,
      };
    },
  });
</script>
<style lang="scss">
  @import './index';
</style>
